home *** CD-ROM | disk | FTP | other *** search
/ Windows Expert / Windows Expert.iso / windownt / uupc11ys.zip / MAIL / MAILLIB.C < prev    next >
C/C++ Source or Header  |  1993-04-10  |  20KB  |  581 lines

  1. /*--------------------------------------------------------------------*/
  2. /*    m a i l l i b . c                                               */
  3. /*                                                                    */
  4. /*    Mail user agent subroutine library for UUPC/extended            */
  5. /*                                                                    */
  6. /*    Changes Copyright (c) 1990-1993 by Kendra Electronic            */
  7. /*    Wonderworks; all rights reserved except those explicitly        */
  8. /*    granted by the UUPC/extended license.                           */
  9. /*--------------------------------------------------------------------*/
  10.  
  11. /*--------------------------------------------------------------------*/
  12. /*    Change History:                                                 */
  13. /*                                                                    */
  14. /*       3 May 90 Create from mail.c                                  */
  15. /*       16 Jun 90:  Added support for mail (~) subcommands      pdm  */
  16. /*                   chgd calling seq of Collect_Mail to support      */
  17. /*                         above                                      */
  18. /*                   chges to CopyMsg to support ~i subcmd            */
  19. /*                   mods to SendMail to support autosign option      */
  20. /*                   broke out signature append code to seperate fn   */
  21. /*                   added support for alternate signature file       */
  22. /*--------------------------------------------------------------------*/
  23.  
  24. /*
  25.  *    $Id: MAILLIB.C 1.3 1993/04/11 00:33:05 ahd Exp $
  26.  *
  27.  *    $Log: MAILLIB.C $
  28.  * Revision 1.3  1993/04/11  00:33:05  ahd
  29.  * Global edits for year, TEXT, etc.
  30.  *
  31.  * Revision 1.2  1992/11/27  14:36:10  ahd
  32.  * Use scrsize() for screen size
  33.  *
  34.  */
  35.  
  36. #include <ctype.h>
  37. #include <stdio.h>
  38. #include <stdlib.h>
  39. #include <string.h>
  40.  
  41. #include "lib.h"
  42. #include "address.h"
  43. #include "hlib.h"
  44. #include "mlib.h"
  45. #include "alias.h"
  46. #include "mail.h"
  47. #include "maillib.h"
  48. #include "scrsize.h"
  49.  
  50. #define  INDENT "> "
  51.  
  52. /*--------------------------------------------------------------------*/
  53. /*       Local variables                                              */
  54. /*--------------------------------------------------------------------*/
  55.  
  56. static int PageCount = 0;
  57.  
  58. static char *ignorelist[] =  { "Message-ID:",
  59.                         "Received:",
  60.                         "Status: ",
  61.                         "X-Mailer: ",
  62.                         "From " ,
  63.                         "Path: ",
  64.                         "Lines: ",
  65.                         "References: ",
  66.                         "" };
  67.  
  68. currentfile();                /* Define current file for panic()     */
  69.  
  70. /*--------------------------------------------------------------------*/
  71. /*    P a g e r                                                       */
  72. /*                                                                    */
  73. /*    Page through a message                                          */
  74. /*                                                                    */
  75. /*    There are hooks here to let the user use his/her own pager,     */
  76. /*    like LIST, MORE, or LESS.  We just write the message out to     */
  77. /*    a temporary file and invoke the appropriate external program    */
  78. /*    to do the browsing.                                             */
  79. /*--------------------------------------------------------------------*/
  80.  
  81. boolean Pager(const int msgnum,
  82.               boolean external,
  83.               copyopt received,
  84.               const boolean reset)
  85. {
  86.    long nextloc;
  87.    char *browse   = NULL;
  88.    char buf[BUFSIZ];
  89.    boolean exit  = FALSE;        /* Flag for PRE-MATURE exit   ahd   */
  90.    FILE *fmailbag;
  91.  
  92.    if (msgnum == -1)
  93.       return FALSE;
  94.  
  95.    if (bflag[F_PAGER])           /* User want pager option inverted? */
  96.       external = ! external;     /* Yes --> Do the inversion         */
  97.  
  98.    if (letters[msgnum].status < M_READ)
  99.       letters[msgnum].status = M_READ;
  100.  
  101.    if (external && (E_pager != nil(char)))
  102.    {
  103.       browse = mktempname( NULL,"TMP" );/* Get a temporary file name */
  104.  
  105.       if ((fmailbag = FOPEN(browse, "w",TEXT_MODE)) == nil(FILE))
  106.       {
  107.          printerr(browse);
  108.          printmsg(0,"Cannot open browse file %s",browse);
  109.          return FALSE;
  110.       } /* if */
  111.       CopyMsg(msgnum, fmailbag, received, FALSE);
  112.       fclose(fmailbag);
  113.  
  114.       L_invoke_pager(E_pager, browse);
  115.       remove(browse);
  116.       free(browse);
  117.  
  118.    } /* if */
  119.    else {
  120.       fseek(fmailbox, letters[msgnum].adr , SEEK_SET);
  121.       nextloc = letters[msgnum + 1].adr;
  122.  
  123.       if ( reset )
  124.          ClearScreen();
  125.       else
  126.          PageLine("\n");
  127.  
  128.       sprintf(buf,"Mailbox item %d:\n",msgnum + 1);
  129.       PageLine(buf);
  130.       while (ftell(fmailbox) < nextloc && (!exit) &&
  131.          fgets(buf, BUFSIZ, fmailbox) != nil(char))
  132.       {
  133.          boolean print = TRUE;
  134.  
  135.          switch(received)
  136.          {
  137.             case nocontinue:
  138.                if ((*buf != '\n') && !isgraph(*buf)) {
  139.                   print = FALSE;
  140.                   break;
  141.                }
  142.                else
  143.                   received = noreceived;
  144.             case noreceived:
  145.             {
  146.                char entry = 0;
  147.                while ( strlen(ignorelist[entry]) && print )
  148.                {
  149.                   if (equalni(ignorelist[entry],
  150.                         buf,strlen(ignorelist[entry])))
  151.                   {
  152.                      print = FALSE;
  153.                      received = nocontinue;
  154.                   }
  155.                   else
  156.                      entry++;
  157.                } /* while */
  158.             } /* case noreceived */
  159.          } /* switch */
  160.          if (received != seperators)
  161.             if (equal(buf,"\n"))
  162.                received = seperators;
  163.  
  164.          if (print)
  165.             if (PageLine(buf))         /* Exit if the user hits Q    */
  166.                exit = TRUE;
  167.       } /* while */
  168.  
  169.       if (equal(buf,"\n") && (!exit))                 /* ahd   */
  170.          putchar('\n');                               /* ahd   */
  171.    } /* else */
  172.  
  173.    return ! exit;
  174. } /*Pager*/
  175.  
  176.  
  177. /*--------------------------------------------------------------------*/
  178. /*    S u b _ P a g e r                                               */
  179. /*       pager for the ~p mail subcommand                             */
  180. /*       page through a mail message currently being entered          */
  181. /*                                                                    */
  182. /*    Clone of the Pager function                                     */
  183. /*--------------------------------------------------------------------*/
  184.  
  185. void Sub_Pager(const char *tinput,
  186.                      boolean external )
  187. {
  188.    boolean exit  = FALSE;        /* Flag for PRE-MATURE exit   ahd   */
  189.  
  190.    if (bflag[ F_PAGER ])
  191.       external = ! external;
  192.  
  193.    if ( external && (E_pager != nil(char)) )
  194.       L_invoke_pager(E_pager, tinput);
  195.    else {
  196.       FILE *finput;
  197.       char buf[BUFSIZ];
  198.       finput = FOPEN(tinput, "r",TEXT_MODE);
  199.       if (finput == NULL) {
  200.          printmsg(0,"Cannot open file %s for display",tinput);
  201.          printerr(tinput);
  202.          return;
  203.       }
  204.       PageReset();
  205.       ClearScreen();
  206.       while ( (!exit) && fgets(buf, BUFSIZ, finput) != nil(char))
  207.       {
  208.         if (PageLine(buf))         /* Exit if the user hits Q  */
  209.            exit = TRUE;
  210.       }
  211.       fclose(finput);
  212.    }
  213.  
  214. } /*Sub_Pager*/
  215.  
  216. /*--------------------------------------------------------------------*/
  217. /*    P a g e R e s e t                                               */
  218. /*                                                                    */
  219. /*    Reset page function to top of page                              */
  220. /*--------------------------------------------------------------------*/
  221.  
  222. void PageReset()
  223. {
  224.    PageCount = 0;
  225. } /*PageReset*/
  226.  
  227. /*--------------------------------------------------------------------*/
  228. /*    P a g e L i n e                                                 */
  229. /*                                                                    */
  230. /*    Print one line when paging through a file                       */
  231. /*--------------------------------------------------------------------*/
  232.  
  233. boolean PageLine(char *line)
  234. {
  235.  
  236.    short pagesize = scrsize() - 3;
  237.    fputs(line, stdout);
  238.  
  239.    PageCount = PageCount + 1 + strlen(line) / 81; /* Handle long lines  */
  240.  
  241.    if (PageCount > (pagesize))
  242.    {
  243.       int c;
  244.       fputs("More?", stdout);
  245.       c = Get_One();
  246.  
  247.       switch (tolower(c))
  248.       {
  249.          case 'q':
  250.          case '\003':
  251.          case 'n':                        /* Because that's what I
  252.                                              keep Pressing           */
  253.          case 'x':
  254.             fputs("\rAborted.\n", stdout);
  255.             return TRUE;
  256.  
  257.          case 'd':
  258.             PageCount = pagesize / 2;     /* Half a Page More */
  259.             break;
  260.  
  261.          case '\r':
  262.             PageCount = pagesize;         /* Only print one line  */
  263.             break;
  264.  
  265.          default:
  266.             PageCount = 0;                /* Print full screen    */
  267.       }
  268.       fputs("\r      \r",stdout);
  269.    }
  270.  
  271.    return FALSE;
  272.  
  273. } /*PageLine*/
  274.  
  275. /*--------------------------------------------------------------------*/
  276. /*    C o p y M s g                                                   */
  277. /*                                                                    */
  278. /*    Copy a message                                                  */
  279. /*                                                                    */
  280. /*    Allows copying message with one or more of the options          */
  281. /*    specified in the copyopt data type.                             */
  282. /*--------------------------------------------------------------------*/
  283.  
  284. boolean CopyMsg(int msgnum, FILE *f, copyopt headers, boolean indent)
  285. {
  286.    long nextloc;
  287.    boolean print;
  288.    char buf[BUFSIZ];
  289.  
  290. /*--------------------------------------------------------------------*/
  291. /*                 Write a separator line, if needed                  */
  292. /*--------------------------------------------------------------------*/
  293.  
  294.    if (headers == seperators)
  295.    {
  296.       if (fputs(MESSAGESEP,f) == EOF)     /* Write out separator line   */
  297.       {
  298.          printerr("CopyMsg");
  299.          panic();
  300.       } /* if (fputs(MESSAGESEP,f) == EOF) */
  301.    } /* if (headers == seperators) */
  302.  
  303. /*--------------------------------------------------------------------*/
  304. /*             else add a one line from line, if desired              */
  305. /*--------------------------------------------------------------------*/
  306.  
  307.    else if (headers == fromheader )
  308.    {
  309.       register char *sp = buf;
  310.       headers = noheader;                 /* Do not print full header       */
  311.       if (RetrieveLine(letters[msgnum].date, buf, LSIZE))
  312.       {
  313.          register char  *sp = buf;
  314.          while (!isspace(*sp))
  315.             sp++;
  316.          while (isspace(*sp))
  317.             sp++;
  318.          fprintf(f,"On %s,", sp );
  319.       } /* if */
  320.  
  321.       if (RetrieveLine(letters[msgnum].from, buf, BUFSIZ))
  322.       {
  323.          while (!isspace(*sp) && (*sp != '\0'))
  324.             sp++;
  325.          BuildAddress( buf, sp );
  326.       } /* if */
  327.       else
  328.          strcpy(buf,"you");   /* Wimp out without admitting it       */
  329.  
  330.       fprintf(f, " %s wrote:\n", buf) ;
  331.    } /* if (headers == fromheader ) */
  332.  
  333. /*--------------------------------------------------------------------*/
  334. /*              Now position to the front of the letter               */
  335. /*--------------------------------------------------------------------*/
  336.  
  337.    fseek(fmailbox, letters[msgnum].adr , SEEK_SET);
  338.    nextloc = letters[msgnum + 1].adr;
  339.  
  340.    while (ftell(fmailbox) < nextloc &&
  341.       fgets(buf, BUFSIZ, fmailbox) != nil(char)) {
  342.  
  343. /*--------------------------------------------------------------------*/
  344. /*               Determine if we should write the line                */
  345. /*--------------------------------------------------------------------*/
  346.  
  347.       print = TRUE;
  348.  
  349.       switch (headers)
  350.       {
  351.          case noheader:
  352.             print = FALSE;
  353.             break;
  354.  
  355.          case nocontinue:
  356.             if ((*buf != '\n') && !isgraph(*buf)) {
  357.                print = FALSE;
  358.                break;
  359.             }
  360.             else
  361.                headers = noreceived;
  362.                /* Fall through ... */
  363.          case noreceived:
  364.          {
  365.             char entry = 0;
  366.             while ( strlen(ignorelist[entry]) && print )
  367.             {
  368.                if (equalni(ignorelist[entry],buf,strlen(ignorelist[entry])))
  369.                {
  370.                   print = FALSE;
  371.                   headers = nocontinue;
  372.                }
  373.                else
  374.                   entry++;
  375.             }
  376.          } /* case noreceived */
  377.                /* Fall through */
  378.          case noseperator:
  379.          case seperators:
  380.             break;
  381.  
  382.          default:
  383.             printmsg(0,"CopyMsg: Bad header copy state of %d",headers);
  384.             panic();
  385.       } /* switch */
  386.  
  387. /*--------------------------------------------------------------------*/
  388. /*                 If we should print the line, do so                 */
  389. /*--------------------------------------------------------------------*/
  390.  
  391.       if (print)
  392.       {
  393.          if (indent)
  394.          {
  395.             if ( fputs(INDENT , f ) == EOF )
  396.             {
  397.                printerr( "CopyMsg" );
  398.                panic();
  399.             } /* if ( fputs(INDENT , f ) == EOF ) */
  400.          } /* if (indent) */
  401.  
  402.          if ( fputs(buf , f ) == EOF )
  403.          {
  404.             printerr( "CopyMsg" );
  405.             panic();
  406.          } /* if ( fputs(buf , f ) == EOF ) */
  407.  
  408.       } /* if (print) */
  409.  
  410. /*--------------------------------------------------------------------*/
  411. /*  If end of the header, print all data until the end of the input   */
  412. /*--------------------------------------------------------------------*/
  413.  
  414.       if ( (headers != seperators) && equal(buf, "\n") )
  415.          headers = seperators;
  416.  
  417.    } /*while*/
  418.  
  419.    return TRUE;
  420. } /*CopyMsg*/
  421.  
  422. /*--------------------------------------------------------------------*/
  423. /*    N u m e r i c                                                   */
  424. /*                                                                    */
  425. /*    Determine if a string is numeric.  Returns TRUE if string is    */
  426. /*    numeric, else FALSE.                                            */
  427. /*--------------------------------------------------------------------*/
  428.  
  429.  boolean Numeric( const char *number)
  430.  {
  431.    char *column = (char *) number;
  432.  
  433.    if (*column == '\0')
  434.       return FALSE;
  435.  
  436.    while( isdigit(*column) )  /* Scan to string end or 1st non-digit */
  437.       column++;
  438.  
  439.    return *column == '\0';    /* Success if whole string was made of
  440.                                  digits                              */
  441.  } /* Numeric */
  442.  
  443. /*--------------------------------------------------------------------*/
  444. /*    R e t r i e v e L i n e                                         */
  445. /*                                                                    */
  446. /*    Read a line from a mail header, if available                    */
  447. /*--------------------------------------------------------------------*/
  448.  
  449. boolean RetrieveLine(long adr, char *line, const size_t len)
  450. {
  451.    char *cp = line;
  452.    size_t count;
  453.  
  454.    *line = '\0';              /* Insure nothing to find              */
  455.    if (adr == MISSING)        /* No information to read?             */
  456.       return FALSE;           /* Report this to caller               */
  457.  
  458.    if (fseek(fmailbox, adr, SEEK_SET)) /* Position to data           */
  459.    {                          /* Have a problem?                     */
  460.       printerr("mailbox");    /* Yes --> Report and return           */
  461.       return FALSE;
  462.    }
  463.  
  464. /*--------------------------------------------------------------------*/
  465. /*                     Actually read the data in                      */
  466. /*--------------------------------------------------------------------*/
  467.  
  468.    count = fread(line, sizeof *line, len-1, fmailbox);
  469.  
  470.    if ((count < (len-1)) && ferror( fmailbox ))
  471.    {
  472.       printerr( "RetrieveLine");
  473.       return FALSE;
  474.    }
  475.  
  476.    line[count] = '\0';        /* Terminate the string read           */
  477.  
  478. /*--------------------------------------------------------------------*/
  479. /*    A field continues until a new field begins in column of the     */
  480. /*    next line or the header ends (an empty line); find the end      */
  481. /*    of the field, trimming extra white space from the beginning     */
  482. /*    of each line as we go                                           */
  483. /*--------------------------------------------------------------------*/
  484.  
  485.    while( (cp = strchr(cp , '\n')) != NULL )
  486.    {
  487.       if ((cp[1] == '\n') || !isspace(cp[1]))   /* End of field?     */
  488.          *cp = '\0';          /* Yes --> Terminate string            */
  489.       else {
  490.          char *next;
  491.  
  492.          *cp++ = ' ';         /* Convert line break to whitespace    */
  493.          next = ++cp;         /* Get first position of new line      */
  494.          while( isspace( *next ) )  /* Ignore leading white space    */
  495.             next++;
  496.  
  497.          memmove( cp , next , strlen(next) + 1 );
  498.                               /* Trim leading white space            */
  499.       } /* else */
  500.    } /* while */
  501.  
  502.    return TRUE;
  503.  
  504. } /*RetrieveLine*/
  505.  
  506. /*--------------------------------------------------------------------*/
  507. /*    R e t u r n A d d r e s s                                       */
  508. /*                                                                    */
  509. /*    Returns the user name (if available and requested) or           */
  510. /*    E-mail address of the user                                      */
  511. /*                                                                    */
  512. /*    Written by ahd 15 July 1989                                     */
  513. /*--------------------------------------------------------------------*/
  514.  
  515. void ReturnAddress(char *line, struct ldesc *ld)
  516. {
  517.    char buffer[BUFSIZ];
  518.  
  519.    if (!RetrieveLine(ld->from, buffer, BUFSIZ))
  520.                                           /* From: line available?   */
  521.       strcpy(line,"-- Unknown --");       /* No --> Return error     */
  522.    else {
  523.       char *begin = buffer;
  524.       while (!isspace(*begin) && (*begin != '\0'))
  525.          begin++;
  526.       if (strlen(begin))
  527.          ExtractName(line,begin);         /* Yes --> Return name     */
  528.       else
  529.          strcpy(line,"-- Invalid From: line --");
  530.    }
  531.  
  532.    return;
  533.  
  534. } /*ReturnAddress*/
  535.  
  536. /*--------------------------------------------------------------------*/
  537. /*    s a y o p t i o n s                                             */
  538. /*                                                                    */
  539. /*    Announce user options in effect                                 */
  540. /*--------------------------------------------------------------------*/
  541.  
  542. void sayoptions( FLAGTABLE *flags)
  543. {
  544.  
  545.    size_t subscript;
  546.    size_t used = 0;
  547.  
  548.    printf("\nThe following options are set:\n");
  549.  
  550.    for (subscript = 0; (subscript < F_LAST); subscript++)
  551.    {
  552.          size_t width;
  553.  
  554.          if (flags[subscript].bits & B_GLOBAL)
  555.             continue;               /* Don't print system options */
  556.  
  557.          width = 1 + strlen( flags[subscript].sym ) +
  558.                  ( bflag[ flags[subscript].position ] ? 0 : 2 );
  559.  
  560.          used += width;
  561.          if ( subscript > 0 )
  562.          {
  563.             if ( used > 79 )
  564.             {
  565.                putchar('\n');
  566.                used = width;
  567.             } /* if ( used > 79 ) */
  568.             else
  569.                putchar(' ');
  570.          } /* if ( subscript > 0 ) */
  571.  
  572.          printf("%s%s",
  573.             bflag[ flags[subscript].position ] ? "" : "no" ,
  574.             flags[subscript].sym );
  575.  
  576.    } /* for */
  577.  
  578.    putchar('\n');
  579.  
  580. } /* sayoptions */
  581.